import functools
from django.urls import reverse
from django.contrib.auth import settings, login
from django.core.cache import cache
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView, View, ListView
from django.http.response import HttpResponseBadRequest, HttpResponse, HttpResponseRedirect
from wechatpy.utils import check_signature as wechatpy_check_signature
from wechatpy.exceptions import InvalidSignatureException
from wechatpy.oauth import WeChatOAuth
from wechatpy import WeChatClient, parse_message
from wechatpy.replies import TextReply, EmptyReply, TransferCustomerServiceReply

from .models import OneBookUser, Content, WxAutoReply


def oauth(scope='snsapi_userinfo'):
	"""
	网页授权装饰器，一般放在view的get方法上就行
	:param scope: snsapi_userinfo | snsapi_base
	:return:
	"""
	def decorator(func):
		@functools.wraps(func)
		def wrapper(self, request, *args, **kwargs):
			# 用户已登录且access_token未到期
			if request.user.is_authenticated:
				return func(self, request, *args, **kwargs)

			# access_token已到期，重新获取
			else:
				oauth = WeChatOAuth(settings.WECHAT['appid'],
									settings.WECHAT['secret'],
									settings.DOMAIN + request.path,
									scope=self.SCOPE)
				code = request.GET.get('code', None)

				if code is None:
					return HttpResponseRedirect(oauth.authorize_url)
				else:
					access_token = oauth.fetch_access_token(code)
					info = oauth.get_user_info()

					user, is_created = OneBookUser.objects.get_or_create(username=info['nickname'],
																		 openid=info['openid'],
																		 unionid=info['unionid'],
																		 sex=info['sex'],
																		 city=info['city'],
																		 province=info['province'],
																		 headimgurl=info['headimgurl'])
					login(request, user)
			return func(self, request, *args, **kwargs)
		return wrapper
	return decorator


def check_signature(func):
	@functools.wraps(func)
	def get(self, request, *args, **kwargs):
		try:
			wechatpy_check_signature(settings.WECHAT['token'],
									 request.GET['signature'],
									 request.GET['timestamp'],
									 request.GET['nonce'])
		except InvalidSignatureException:
			return HttpResponseBadRequest('InvalidSignatureException')

		# 是否为验证请求
		echostr = request.GET.get('echostr')
		if echostr:
			return HttpResponse(echostr)
		else:
			return func(self, request, *args, **kwargs)
	return get


@method_decorator(csrf_exempt, name='dispatch')
class WeChatDispatchView(View):
	@check_signature
	def get(self, request, *args, **kwargs):
		return HttpResponse('hello world')

	@check_signature
	def post(self, request, *args, **kwargs):
		msg = parse_message(request.body)
		ret = EmptyReply().render()
		if msg.type == 'text':
			if msg.content == '人工':
				ret = self.kf(request, msg)
			else:
				ret = self.text(request, msg)
		return HttpResponse(ret)

	def text(self, request, msg):
		try:
			obj = WxAutoReply.objects.get(keyword=msg.content)
		except WxAutoReply.DoesNotExist:
			return EmptyReply().render()
		# 回复第一条信息
		reply = obj.contents.all()[0]
		return reply.get_reply(msg).render() + reply.get_reply(msg).render()

	def kf(self, request, msg):
		reply = TransferCustomerServiceReply(message=msg)
		return reply.render()


class OAuthView(View):
	"""
	必须在微信中打开，自动获取用户信息并通过cookies建立会话
	"""
	SCOPE = 'snsapi_userinfo'

	def dispatch(self, request, *args, **kwargs):
		# 用户已登录且access_token未到期
		if request.user.is_authenticated:
			return super().dispatch(request, *args, *kwargs)

		# access_token已到期，重新获取
		else:
			oauth = WeChatOAuth(settings.WECHAT['appid'],
								settings.WECHAT['secret'],
								settings.DOMAIN + request.path,
								scope=self.SCOPE)
			code = request.GET.get('code', None)

			if code is None:
				return HttpResponseRedirect(oauth.authorize_url)
			else:
				access_token = oauth.fetch_access_token(code)
				info = oauth.get_user_info()

				user, is_created = OneBookUser.objects.update_or_create(username=info['nickname'],
																		openid=info['openid'],
																		unionid=info['unionid'],
																		sex=info['sex'],
																		city=info['city'],
																		province=info['province'],
																		headimgurl=info['headimgurl'])
				login(request, user)
			return super().dispatch(request, *args, **kwargs)


class IndexView(OAuthView, TemplateView):
	template_name = 'resource/index.html'


class ChatRoomView(TemplateView):
	template_name = 'resource/room.html'
